/*
 * StateGame.cpp
 *
 *  Created on: 06/04/2013
 *      Author: Vitor
 */

#include "StateGame.h"

StateGame::StateGame() {
}

StateGame::~StateGame() {
	this->unload();
}

StateArgs StateGame::unload() {
	backgroundMusic->stop();

	BulletManager::cleanUp();

	delete (tileMap);
	delete (tileSet);
	delete (earth);
	delete (moon);
	delete (ufo);
	delete (ship);
	delete (background);
	delete (redPlanetSprite);
	delete (earthSprite);
	delete (moonSprite);
	delete (ufoSprite);
	delete (bulletSprite);
	delete (redLifeBarBlockSprite);
	delete (yellowLifeBarBlockSprite);
	delete (lifeContainerBotSprite);
	delete (lifeContainerMidSprite);
	delete (lifeContainerTopSprite);
	delete (shipAnimation);
	delete (boom);
	delete (boomExplosion);
	delete (backgroundMusic);
	delete (shipCommands);
	delete (ufoMoveCommands);
	delete (ufoPlanetCommands);
	delete (pauseCommand);

	// Desaloca os planetas que restaram
	for (std::vector<Planet*>::iterator it = planetArray.begin();
			it != planetArray.end(); it++) {
		delete *it;
	}
	return StateArgs();
}

void StateGame::load(StateArgs arguments) {
	this->arguments = arguments;

	SDL_Color color;
	color.r = 255;
	color.g = 255;
	color.b = 255;

	quit = false;
	pause = false;

	background = new Sprite("../gfx/fundo.png");
	redPlanetSprite = new Sprite("../gfx/PlanetaVermelho.png");
	earthSprite = new Sprite("../gfx/PlanetaTerra.png");
	earthSprite->rotoZoom(0, 3, 3, false);
	moonSprite = new Sprite("../gfx/Lua.png");
	ufoSprite = new Sprite("../gfx/ufo.png");
	bulletSprite = new Sprite("../gfx/bulletSprite.png");
	redLifeBarBlockSprite = new Sprite("../gfx/blocoVidaVermelho.png");
	yellowLifeBarBlockSprite = new Sprite("../gfx/blocoVidaAmarelo.png");
	lifeContainerBotSprite = new Sprite("../gfx/containerVidaBot.png");
	lifeContainerMidSprite = new Sprite("../gfx/containerVidaMid.png");
	lifeContainerTopSprite = new Sprite("../gfx/containerVidaTop.png");

	shipAnimation = new Animation("../gfx/NaveSheet.png", 200, 4);
	boom = new Animation("../gfx/BoomSheet.png", 60, 8);

	shipCommands = new Text("../ttf/DiabloLight.ttf",
			"Para mover a nave, use as teclas WASD.", 15, 0, color, 0, 0);
	ufoMoveCommands = new Text("../ttf/DiabloLight.ttf",
			"Para mover o UFO, use o botao direito do mouse.", 15, 0, color, 0,
			20);
	ufoPlanetCommands =
			new Text("../ttf/DiabloLight.ttf",
					"Para criar novos planetas, utilize o botao esquerdo do mouse com o UFO.",
					15, 0, color, 0, 40);
	pauseCommand = new Text("../ttf/DiabloLight.ttf",
			"Para pausar, aperte 'Enter'", 15, 0, color, 0, 60);

	boomExplosion = new Sound("../snd/boom.wav");
	backgroundMusic = new Music("../snd/stateGame.mp3");

	earth = new Earth(earthSprite, (rand() % 4000) - 1000,
			(rand() % 4000) - 1000, 1);
	moon = new Moon(moonSprite, 1, earth);
	ufo = new FollowerObject(ufoSprite, 600, 300);
	ship = new AcceleratedObject(shipAnimation, 200, 100,
			shipAnimation->getWidth() / shipAnimation->getNumSprites(),
			shipAnimation->getHeight(), 20);

	tileSet = new TileSet("../gfx/Tileset.png", TILE_SIZE, TILE_SIZE);

	tileMap = new TileMap("../map/tileMap.txt", tileSet);

	cameraSpeed.x = cameraSpeed.y = 0;

	backgroundMusic->play(-1);

	planetTimer.start(PLANET_COOLDOWN);

	lifeContainerSize = ship->getHitPoints();
}

void StateGame::addPlanet() {
	Planet* toAdd;

	toAdd = new PlanetRed(redPlanetSprite, (rand() % 20) + 1,
			(rand() % 800) + Camera::camera.getX(),
			(rand() % 600) + Camera::camera.getY(), ship, bulletSprite);

	planetArray.push_back(toAdd);
}

void StateGame::checkPlanets(int dt) {
	for (std::vector<Planet*>::iterator it = planetArray.begin();
			it != planetArray.end(); it++) {
		(*it)->update(dt);

		if ((*it)->isDead()) {
			it = planetArray.erase(it);
			it--;
		}

	}
}

void StateGame::input() {

	if (InputManager::getInstance()->isMouseDown(SDL_BUTTON_LEFT)
			&& planetTimer.isDone()) {
		addPlanet();
		planetTimer.start(PLANET_COOLDOWN);
	}

	if (InputManager::getInstance()->isMouseDown(SDL_BUTTON_RIGHT) && ufo)
		ufo->enqueueCommand(
				Point(
						InputManager::getInstance()->mousePosX()
								+ Camera::camera.getX(),
						InputManager::getInstance()->mousePosY()
								+ Camera::camera.getY()));

	if (InputManager::getInstance()->QuitGame()
			|| InputManager::getInstance()->isKeyDown(SDLK_ESCAPE)) {
		quit = true;
	}

	if (InputManager::getInstance()->isKeyDown(SDLK_RETURN))
		pause = true;

}

int StateGame::update(double dt) {

	backgroundMusic->setVolume(64);
	resumeAllTimers();

	planetTimer.update();
	shipWinTimer.update();
	ufoWinTimer.update();

	if (ship && ufo) {
		Camera::camera.setX(ship->getBox()->getPositionRef()->getX() - 400);
		Camera::camera.setY(ship->getBox()->getPositionRef()->getY() - 300);
	}

	if (ship)
		ship->update(dt);
	if (ufo)
		ufo->update(dt);

	earth->update(dt);
	moon->update(dt);
	boom->update(dt);
	BulletManager::update(dt);

	// Atualiza��o dos objetos
	checkPlanets(dt);
	checkCollisions(dt);

	nextState = SDLBase::STATENOCHANGE;

	if (quit)
		nextState = SDLBase::STATEQUIT;
	if (pause) {
		nextState = SDLBase::STATEPAUSE;
		backgroundMusic->setVolume(32);
		pauseAllTimers();
		pause = false;
	}
	if (!ufo && shipWinTimer.isDone())
		nextState = SDLBase::STATEWIN;
	if (!ship && ufoWinTimer.isDone())
		nextState = SDLBase::STATELOSE;

	return nextState;
}

void StateGame::checkCollisions(int dt) {

	if (ship && ufo) {
		for (std::vector<Planet*>::iterator it = planetArray.begin();
				it != planetArray.end(); it++) {
			if (ship->collidesWith(*it)) {
				ship->setHitPoints(ship->getHitPoints() - 1);
				boomPos = *((*it)->getBox()->getPositionRef());
				boomExplosion->play(1);
				it = planetArray.erase(it);
				it--;
			}
		}

		Bullet* tempBullet;

		/* Um tiro colidiu com a nave */
		if ((tempBullet = BulletManager::checkCollision(ship, false)) != NULL) {
			ship->setHitPoints(ship->getHitPoints() - 1);
			boomPos = *(tempBullet->getBox()->getPositionRef());
			boomExplosion->play(1);
			tempBullet->setDead(true);
		}

		if (ship->collidesWith(ufo)) {
			ship->setHitPoints(0);
		}

		/*Nave morreu*/
		if (ship->getHitPoints() <= 0) {
			boomPos = *(ship->getBox()->getPositionRef());
			boomExplosion->play(1);
			delete (ship);
			ship = NULL;
			ufoWinTimer.start(1500);
			return;
		}

		if (ship->collidesWith(earth)) {
			boomPos = *(ufo->getBox()->getPositionRef());
			boomExplosion->play(1);
			delete (ufo);
			ufo = NULL;
			shipWinTimer.start(1500);
			return;
		}
	}

}

void StateGame::render() {
	// Comandos de renderiza��o
	background->render(0, 0, false);

	tileMap->render(Camera::camera.getX(), Camera::camera.getY());

	BulletManager::render(Camera::camera.getX(), Camera::camera.getY());

	for (std::vector<Planet*>::iterator it = planetArray.begin();
			it != planetArray.end(); ++it) {
		(*it)->render(Camera::camera.getX(), Camera::camera.getY());
	}

	if (ship)
		ship->render(Camera::camera.getX(), Camera::camera.getY());
	if (ufo)
		ufo->render(Camera::camera.getX(), Camera::camera.getY());
	if (boomPos.getX() != 0 || boomPos.getY() != 0)
		boom->render(boomPos.getX() - Camera::camera.getX(),
				boomPos.getY() - Camera::camera.getY(), true);

	earth->render(Camera::camera.getX(), Camera::camera.getY());
	moon->render(Camera::camera.getX(), Camera::camera.getY());

	renderLifeBar();

	shipCommands->render(0, 0, false);
	ufoMoveCommands->render(0, 0, false);
	ufoPlanetCommands->render(0, 0, false);
	pauseCommand->render(0, 0, false);
}

void StateGame::renderLifeBar() {

	Point initialPosition(20, 450);
	int i;

	// Imprime o container de vida
	lifeContainerBotSprite->render(initialPosition.getX(),
			initialPosition.getY(), true);

	for (i = 1; i < lifeContainerSize - 1; i++) {
		lifeContainerMidSprite->render(initialPosition.getX(),
				initialPosition.getY()
						- i * lifeContainerMidSprite->getHeight(), true);
	}

	lifeContainerTopSprite->render(initialPosition.getX(),
			initialPosition.getY() - i * lifeContainerMidSprite->getHeight(),
			true);

	if (ship) {
		// Imprime as barras amarelas de vida
		for (i = 0; i < ship->getHitPoints(); i++) {
			yellowLifeBarBlockSprite->render(initialPosition.getX(),
					initialPosition.getY()
							- i * yellowLifeBarBlockSprite->getHeight(), true);
		}

		// Imprime as barras vermelhas de vida
		for (i = 0; i < std::min(3, ship->getHitPoints()); i++) {
			redLifeBarBlockSprite->render(initialPosition.getX(),
					initialPosition.getY()
							- i * redLifeBarBlockSprite->getHeight(), true);
		}
	}
}

void StateGame::pauseAllTimers() {
	planetTimer.pause();
	ufoWinTimer.pause();
	shipWinTimer.pause();
}

void StateGame::resumeAllTimers() {
	planetTimer.resume();
	ufoWinTimer.resume();
	shipWinTimer.resume();
}
